var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var Geo;
(function (Geo) {
    var String = (function () {
        function String() {
        }
        String.Parse = function Parse(arg) {
            return arg;
        };
        String.IsNull = function IsNull(arg, def) {
            return (arg === undefined || arg === null) ? def : arg;
        };
        return String;
    })();
    Geo.String = String;    
    (function (Enumerations) {
        (function (ActionTypes) {
            ActionTypes._map = [];
            ActionTypes.Travel = 0;
            ActionTypes.PickUp = 1;
            ActionTypes.DropOff = 2;
        })(Enumerations.ActionTypes || (Enumerations.ActionTypes = {}));
        var ActionTypes = Enumerations.ActionTypes;
        (function (GeoCacheSiteTypes) {
            GeoCacheSiteTypes._map = [];
            GeoCacheSiteTypes.GeocachingDotCom = 0;
            GeoCacheSiteTypes.OpenCachingDotCom = 1;
            GeoCacheSiteTypes.OpenCachingDotUs = 2;
        })(Enumerations.GeoCacheSiteTypes || (Enumerations.GeoCacheSiteTypes = {}));
        var GeoCacheSiteTypes = Enumerations.GeoCacheSiteTypes;
    })(Geo.Enumerations || (Geo.Enumerations = {}));
    var Enumerations = Geo.Enumerations;
        (function (Model) {
        var PrivateKeyInfo = (function () {
            function PrivateKeyInfo(privateKey) {
                this.privateKey = privateKey;
                this.privateKey = privateKey;
            }
            Object.defineProperty(PrivateKeyInfo.prototype, "PrivateKey", {
                get: function () {
                    return this.privateKey;
                },
                enumerable: true,
                configurable: true
            });
            return PrivateKeyInfo;
        })();
        Model.PrivateKeyInfo = PrivateKeyInfo;        
        var PublicKeyInfo = (function () {
            function PublicKeyInfo(publicKey) {
                this.publicKey = publicKey;
                this.publicKey = publicKey;
            }
            Object.defineProperty(PublicKeyInfo.prototype, "PublicKey", {
                get: function () {
                    return this.publicKey;
                },
                enumerable: true,
                configurable: true
            });
            return PublicKeyInfo;
        })();
        Model.PublicKeyInfo = PublicKeyInfo;        
        var ContextInfo = (function () {
            function ContextInfo(logEntryLid, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith, isOnlineFunc, isProduction) {
                this._isOnlineFunc = isOnlineFunc;
                this.IsProduction = isProduction;
                this.LogEntryLid = logEntryLid;
                if(privateKey) {
                    this.PrivateKey = privateKey.PrivateKey;
                }
                this.ActionType = actionType;
                this.UserInteractedWith = userInteractedWith;
                this.CacheCode = cacheCode;
                this.CacheSiteType = cacheSiteType;
                this.Coordinates = coordinates;
            }
            ContextInfo.prototype.IsOnline = function () {
                return this._isOnlineFunc();
            };
            return ContextInfo;
        })();
        Model.ContextInfo = ContextInfo;        
        var NameValuePairInfo = (function () {
            function NameValuePairInfo(name, value) {
                this.Name = name;
                this.Value = value;
            }
            return NameValuePairInfo;
        })();
        Model.NameValuePairInfo = NameValuePairInfo;        
        var LogEntryIdInfo = (function () {
            function LogEntryIdInfo(logEntryLid) {
                this.LogEntryLid = logEntryLid;
            }
            return LogEntryIdInfo;
        })();
        Model.LogEntryIdInfo = LogEntryIdInfo;        
        var LogEntryInfo = (function (_super) {
            __extends(LogEntryInfo, _super);
            function LogEntryInfo(logEntryLid, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith) {
                        _super.call(this, logEntryLid);
                this.PrivateKey = privateKey.PrivateKey;
                this.ActionType = actionType;
                this.UserInteractedWith = userInteractedWith;
                this.CacheCode = cacheCode;
                this.CacheSiteType = cacheSiteType;
                this.Coordinates = coordinates;
            }
            return LogEntryInfo;
        })(LogEntryIdInfo);
        Model.LogEntryInfo = LogEntryInfo;        
    })(Geo.Model || (Geo.Model = {}));
    var Model = Geo.Model;
    (function (Controller) {
        var TypedEvent = (function () {
            function TypedEvent() {
                this._listeners = [];
            }
            TypedEvent.prototype.add = function (listener) {
                this._listeners.push(listener);
            };
            TypedEvent.prototype.remove = function (listener) {
                if(typeof listener === 'function') {
                    for(var i = 0, l = this._listeners.length; i < l; l++) {
                        if(this._listeners[i] === listener) {
                            this._listeners.splice(i, 1);
                            break;
                        }
                    }
                } else {
                    this._listeners = [];
                }
            };
            TypedEvent.prototype.trigger = function () {
                var a = [];
                for (var _i = 0; _i < (arguments.length - 0); _i++) {
                    a[_i] = arguments[_i + 0];
                }
                var context = {
                };
                var listeners = this._listeners.slice(0);
                for(var i = 0, l = listeners.length; i < l; i++) {
                    listeners[i].apply(context, a || []);
                }
            };
            return TypedEvent;
        })();
        Controller.TypedEvent = TypedEvent;        
        var Helper = (function () {
            function Helper() {
            }
            Helper.prototype.queryString = function (queryStringRaw, arg) {
                var qsSegment = queryStringRaw.split("&");
                for(var i = 0; i < qsSegment.length; i++) {
                    var nvp = qsSegment[i].split("=");
                    if(nvp[0] == arg) {
                        return nvp[1];
                    }
                }
            };
            return Helper;
        })();
        Controller.Helper = Helper;        
        var SessionNameValuePairs = (function () {
            function SessionNameValuePairs() { }
            SessionNameValuePairs.prototype.Clear = function () {
                sessionStorage.clear();
            };
            SessionNameValuePairs.prototype.Get = function (key) {
                return sessionStorage[key];
            };
            SessionNameValuePairs.prototype.Set = function (key, value) {
                sessionStorage[key] = value;
            };
            return SessionNameValuePairs;
        })();
        Controller.SessionNameValuePairs = SessionNameValuePairs;        
        var QueryStringNameValuePairs = (function () {
            function QueryStringNameValuePairs(queryString) {
                this._items = new Array();
                for(var i = 0; i < queryString.length; i++) {
                    var nvp = queryString[i].split("=");
                    this._items.push(new Model.NameValuePairInfo(nvp[0], nvp[1]));
                }
            }
            QueryStringNameValuePairs.prototype.Clear = function () {
                this._items = [];
            };
            QueryStringNameValuePairs.prototype.Get = function (key) {
                for(var i = 0; i < this._items.length; i++) {
                    if(this._items[i].Name == key) {
                        return this._items[i].Value;
                    }
                }
                return null;
            };
            QueryStringNameValuePairs.prototype.Set = function (key, value) {
                var wasSet = false;
                for(var i = 0; i < this._items.length; i++) {
                    if(this._items[i].Name == key) {
                        this._items[i].Value = value;
                        wasSet = true;
                    }
                }
                if(!wasSet) {
                    this._items.push(new Model.NameValuePairInfo(key, value));
                }
            };
            return QueryStringNameValuePairs;
        })();
        Controller.QueryStringNameValuePairs = QueryStringNameValuePairs;        
        var SessionNavigationProvider = (function () {
            function SessionNavigationProvider(nameValuePairs, navigationFunc) {
                this._nameValuePairs = nameValuePairs;
                this._navigationFunc = navigationFunc;
            }
            SessionNavigationProvider.prototype.GoTo = function (url) {
                var pairs = [];
                for (var _i = 0; _i < (arguments.length - 1); _i++) {
                    pairs[_i] = arguments[_i + 1];
                }
                this.GoToMulti(url, pairs);
            };
            SessionNavigationProvider.prototype.GoToMulti = function (url, pairs) {
                sessionStorage.clear();
                if(pairs.length > 0) {
                    for(var i = 0; i < pairs.length; i++) {
                        this._nameValuePairs.Set(pairs[i].Name, pairs[i].Value);
                    }
                }
                this._navigationFunc(url);
            };
            return SessionNavigationProvider;
        })();
        Controller.SessionNavigationProvider = SessionNavigationProvider;        
        var QueryStringNavigationProvider = (function () {
            function QueryStringNavigationProvider(navigationFunc) {
                this.NavigationFunc = navigationFunc;
            }
            QueryStringNavigationProvider.prototype.GoTo = function (url) {
                var pairs = [];
                for (var _i = 0; _i < (arguments.length - 1); _i++) {
                    pairs[_i] = arguments[_i + 1];
                }
                this.GoToMulti(url, pairs);
            };
            QueryStringNavigationProvider.prototype.GoToMulti = function (url, pairs) {
                var queryString = '';
                if(pairs.length > 0) {
                    queryString = '?';
                    for(var i = 0; i < pairs.length; i++) {
                        if(i > 0) {
                            queryString += '&';
                        }
                        queryString += pairs[i].Name + '=' + pairs[i].Value;
                    }
                }
                this.NavigationFunc(url + queryString);
            };
            return QueryStringNavigationProvider;
        })();
        Controller.QueryStringNavigationProvider = QueryStringNavigationProvider;        
        var GenericNavigationProvider = (function () {
            function GenericNavigationProvider(getNavigationProviderFunc) {
                this.GetNavigationProviderFunc = getNavigationProviderFunc;
            }
            GenericNavigationProvider.prototype.GoTo = function (url) {
                var pairs = [];
                for (var _i = 0; _i < (arguments.length - 1); _i++) {
                    pairs[_i] = arguments[_i + 1];
                }
                this.GoToMulti(url, pairs);
            };
            GenericNavigationProvider.prototype.GoToMulti = function (url, pairs) {
                this.GetNavigationProviderFunc().GoToMulti(url, pairs);
            };
            return GenericNavigationProvider;
        })();
        Controller.GenericNavigationProvider = GenericNavigationProvider;        
        var NavigationController = (function () {
            function NavigationController(code, language, navigationProvider) {
                this.Code = code;
                this.Language = language;
                this.NavigationProvider = navigationProvider;
            }
            NavigationController.prototype.GoToEntry = function () {
                var url = '/' + this.Language + '/';
                this.NavigationProvider.GoTo(url);
            };
            NavigationController.prototype.GoToAction = function (arg) {
                var url = '/' + this.Language + '/trackable/Action.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)));
            };
            NavigationController.prototype.GoToView = function (arg) {
                var url = '/' + this.Language + '/trackable/GoToView.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)));
            };
            NavigationController.prototype.GoToActionDetail = function (actionType, arg) {
                var url = '/' + this.Language + '/trackable/ActionDetail.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            };
            NavigationController.prototype.GoToUser = function (actionType, arg) {
                var url = '/' + this.Language + '/trackable/User.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            };
            NavigationController.prototype.GoToLocation = function (actionType, arg) {
                var url = '/' + this.Language + '/trackable/Location.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            };
            NavigationController.prototype.GoToGeocache = function (actionType, arg) {
                var url = '/' + this.Language + '/trackable/Geocache.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('c', (arg || this.Code.PrivateKey)), new Model.NameValuePairInfo('at', String.Parse(actionType)));
            };
            NavigationController.prototype.GoToActionEdit = function (lid) {
                var url = '/' + this.Language + '/trackable/User.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            };
            NavigationController.prototype.GoToUserEdit = function (lid) {
                var url = '/' + this.Language + '/trackable/User.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            };
            NavigationController.prototype.GoToLocationEdit = function (lid) {
                var url = '/' + this.Language + '/trackable/Location.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            };
            NavigationController.prototype.GoToGeocacheEdit = function (lid) {
                var url = '/' + this.Language + '/trackable/Geocache.html';
                this.NavigationProvider.GoTo(url, new Model.NameValuePairInfo('e', String.Parse(lid)));
            };
            return NavigationController;
        })();
        Controller.NavigationController = NavigationController;        
        var EnglishLabelProvider = (function () {
            function EnglishLabelProvider() {
                this.actionTypesLabels = [
                    'Moved', 
                    'Picked Up', 
                    'Dropped Off'
                ];
                this.geoCacheSiteTypesLabels = [
                    'Geocaching.com', 
                    ' OpenCaching.com', 
                    'OpenCaching.us'
                ];
            }
            EnglishLabelProvider.prototype.GetActionTypeLabel = function (actionType) {
                if(actionType == undefined) {
                    return null;
                }
                return this.actionTypesLabels[actionType];
            };
            EnglishLabelProvider.prototype.GetGeoCacheSiteTypesLabel = function (geoCacheSiteType) {
                if(geoCacheSiteType == undefined) {
                    return null;
                }
                return this.geoCacheSiteTypesLabels[geoCacheSiteType];
            };
            return EnglishLabelProvider;
        })();
        Controller.EnglishLabelProvider = EnglishLabelProvider;        
        var LocationProvider = (function () {
            function LocationProvider(onBeforeInitialize, locationRepository, isAvailable) {
                this._onLocationUpdated = onBeforeInitialize;
                this._locationRepository = locationRepository;
                this._isAvailable = isAvailable;
                locationRepository.GetPosition(this.CurrentPositionResult, this.CurrentPositionError);
            }
            LocationProvider.prototype.CurrentPositionResult = function (result) {
                alert(result.Latitude + ' ' + result.Longitude);
            };
            LocationProvider.prototype.CurrentPositionError = function (error) {
                alert(error);
            };
            Object.defineProperty(LocationProvider.prototype, "OnLocationUpdated", {
                get: function () {
                    return this._onLocationUpdated;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(LocationProvider.prototype, "IsAvailable", {
                get: function () {
                    return this._isAvailable;
                },
                enumerable: true,
                configurable: true
            });
            return LocationProvider;
        })();
        Controller.LocationProvider = LocationProvider;        
    })(Geo.Controller || (Geo.Controller = {}));
    var Controller = Geo.Controller;
    (function (Repositories) {
        var LocalStorageLogEntryRepository = (function () {
            function LocalStorageLogEntryRepository() {
                this.KeyLogEntries = 'LogEntries';
                this.KeyLastLogEntryLId = 'LastLogEntryLId';
            }
            LocalStorageLogEntryRepository.prototype.Count = function () {
                var logEntries = this.GetList();
                if(!logEntries) {
                    return 0;
                }
                return logEntries.length;
            };
            LocalStorageLogEntryRepository.prototype.Clear = function () {
                window.localStorage.setItem(this.KeyLogEntries, null);
            };
            LocalStorageLogEntryRepository.prototype.Contains = function (logEntry) {
                var logEntries = this.GetList();
                if(!logEntries) {
                    return false;
                }
                for(var logIndex in logEntries) {
                    if(logEntries[logIndex].LogEntryLid === logEntry.LogEntryLid) {
                        return true;
                    }
                }
                return false;
            };
            LocalStorageLogEntryRepository.prototype.Add = function (privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith) {
                var logEntries = this.GetList();
                if(!logEntries) {
                    logEntries = new Array();
                }
                var lastLogEntryLidRaw = window.localStorage.getItem(this.KeyLastLogEntryLId) || "0";
                var logEntryLid = parseInt(lastLogEntryLidRaw) + 1;
                window.localStorage.setItem(this.KeyLastLogEntryLId, logEntryLid.toString());
                var result = new Model.LogEntryInfo(logEntryLid, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith);
                logEntries[(logEntries) ? logEntries.length : 0] = result;
                this.UpdateList(logEntries);
                return result;
            };
            LocalStorageLogEntryRepository.prototype.Remove = function (logEntry) {
                var logEntriesOriginal = this.GetList();
                var logEntries = new Array();
                var foundIt = false;
                for(var iRaw in logEntriesOriginal) {
                    var i = parseInt(iRaw);
                    if(logEntriesOriginal[i].LogEntryLid === logEntry.LogEntryLid) {
                        foundIt = true;
                    } else {
                        logEntries[(foundIt) ? i - 1 : i] = logEntriesOriginal[i];
                    }
                }
                this.UpdateList(logEntries);
            };
            LocalStorageLogEntryRepository.prototype.Update = function (item) {
                var logEntries = this.GetList();
                for(var i in logEntries) {
                    if(logEntries[i].LogEntryLid = item.LogEntryLid) {
                        logEntries[i] = item;
                    }
                }
            };
            LocalStorageLogEntryRepository.prototype.UpdateList = function (logEntries) {
                var logEntriesRaw = JSON.stringify(logEntries);
                window.localStorage.setItem(this.KeyLogEntries, logEntriesRaw);
            };
            LocalStorageLogEntryRepository.prototype.Get = function (logEntry) {
                var logEntries = this.GetList();
                if(!logEntries) {
                    return null;
                }
                for(var logIndex in logEntries) {
                    if(logEntries[logIndex].LogEntryLid === logEntry.LogEntryLid) {
                        return logEntries[logIndex];
                    }
                }
                return null;
            };
            LocalStorageLogEntryRepository.prototype.GetList = function () {
                var logEntries = null;
                var logEntriesRaw = window.localStorage.getItem(this.KeyLogEntries);
                if(logEntriesRaw == undefined) {
                    return null;
                }
                if(logEntriesRaw != null) {
                    logEntries = JSON.parse(logEntriesRaw);
                }
                return logEntries;
            };
            return LocalStorageLogEntryRepository;
        })();
        Repositories.LocalStorageLogEntryRepository = LocalStorageLogEntryRepository;        
        var GpsGeoLocationRepository = (function () {
            function GpsGeoLocationRepository() { }
            GpsGeoLocationRepository.prototype.GetPosition = function (success, error) {
                navigator.geolocation.getCurrentPosition(function (position) {
                    if(success == undefined) {
                        return;
                    }
                    success(new Geo.CoordinateConverter.Model.CoordinateDecimalInfo(position.coords.latitude, position.coords.longitude));
                }, function (err) {
                    switch(err.code) {
                        case err.PERMISSION_DENIED:
                            break;
                        case err.POSITION_UNAVAILABLE:
                            break;
                        case err.TIMEOUT:
                            break;
                        default:
                            break;
                    }
                });
            };
            return GpsGeoLocationRepository;
        })();
        Repositories.GpsGeoLocationRepository = GpsGeoLocationRepository;        
    })(Geo.Repositories || (Geo.Repositories = {}));
    var Repositories = Geo.Repositories;
    var Core = (function () {
        function Core() { }
        Core.OnBeforeInitialize = new Controller.TypedEvent();
        Core.OnAfterInitialize = new Controller.TypedEvent();
        Core.Initialize = function Initialize(isProduction) {
            this.OnBeforeInitialize.trigger('Core.Initialize|Before');
            this.CoordinateConverter = new Geo.CoordinateConverter.Providers.DecimalAndDmsConverter();
            this.EnumLabelProvider = new Controller.EnglishLabelProvider();
            this.LogEntryRepository = new Repositories.LocalStorageLogEntryRepository();
            this.LocationProvider = new Repositories.GpsGeoLocationRepository();
            var queryStringRaw = window.location.search.substr(1);
            var queryString = new Controller.QueryStringNameValuePairs(queryStringRaw.split("&"));
            var session = new Controller.SessionNameValuePairs();
            var isOnlineFunc = function () {
                return window.navigator.onLine;
            };
            var rawLogEntryLid = queryString.Get('e');
            if(rawLogEntryLid) {
                var logEntry = Geo.Core.LogEntryRepository.Get(new Model.LogEntryIdInfo(parseFloat(rawLogEntryLid)));
                this.Current = new Model.ContextInfo(logEntry.LogEntryLid, logEntry, logEntry.ActionType, logEntry.CacheSiteType, logEntry.CacheCode, logEntry.Coordinates, logEntry.UserInteractedWith, isOnlineFunc, isProduction);
            } else {
                var privateKey = null;
                var privateKeyRaw = queryString.Get('c');
                if(!privateKeyRaw) {
                    privateKeyRaw = session.Get('c');
                }
                if(privateKeyRaw) {
                    privateKey = new Model.PrivateKeyInfo(privateKeyRaw);
                }
                var actionType;
                var actionTypeRaw = queryString.Get('at');
                if(!actionTypeRaw) {
                    actionTypeRaw = session.Get('at');
                }
                if(actionTypeRaw) {
                    actionType = parseInt(actionTypeRaw);
                }
                var cacheCode = queryString.Get('cc');
                if(!cacheCode) {
                    cacheCode = session.Get('cc');
                }
                var cacheSiteType;
                var cacheSiteTypeRaw = queryString.Get('ct');
                if(!actionTypeRaw) {
                    actionTypeRaw = session.Get('ct');
                }
                if(actionTypeRaw) {
                    actionType = parseInt(actionTypeRaw);
                }
                var coordinates;
                var coordinatesRaw = queryString.Get('ll');
                if(!coordinatesRaw) {
                    coordinatesRaw = session.Get('ll');
                }
                if(coordinatesRaw) {
                    coordinates = this.CoordinateConverter.ParseCoordinateDms(coordinatesRaw).ToCoordinateDecimal();
                }
                var userInteractedWith = queryString.Get('ou');
                if(!userInteractedWith) {
                    userInteractedWith = session.Get('ou');
                }
                this.Current = new Model.ContextInfo(null, privateKey, actionType, cacheSiteType, cacheCode, coordinates, userInteractedWith, isOnlineFunc, isProduction);
            }
            var navigationProvider = new Controller.GenericNavigationProvider(function () {
                var navProvider;
                if(Geo.Core.Current.IsOnline()) {
                    navProvider = new Controller.QueryStringNavigationProvider(function (pathAndQuery) {
                        return window.location.href = pathAndQuery;
                    });
                } else {
                    navProvider = new Controller.SessionNavigationProvider(new Controller.SessionNameValuePairs(), function (pathAndQuery) {
                        return window.location.href = pathAndQuery;
                    });
                }
                return navProvider;
            });
            this.Navigation = new Controller.NavigationController(this.Current, 'en', navigationProvider);
            this.OnAfterInitialize.trigger('Core.Initialize|After');
        };
        return Core;
    })();
    Geo.Core = Core;    
})(Geo || (Geo = {}));
